// need the reference "/// <reference path="jquery-x.y.z-vsdoc.js"/>" for jq intellisense to work
// NB: MUST have three '///' not two!

/// <reference path="jquery-1.4.1-vsdoc.js"/>

// globals
var ipaddr,
	usr,
	pwd,
	refreshFreq,
	FAST_REFRESH_FREQ = "500";  // all freq in ms

// array of objects containing the dps to monitor
// each dp has: 
// - descriptive name
// - path to the dp representing the Read() value
// - path to the dp for Write()ing the new value. if empty it's read only dp
// - class used to link the dp value to its html element(s)
// the class is used to select elements in which to show the value of the point (can be used in multiple locations)
var observedDataPoints_Arr = [
	{ dpName: "DO-1", dpReadPath: "Net/LON/iLON App/Digital Output 1/nvoClaValueFb_1", dpWritePath: "Net/LON/iLON App/Digital Output 1/nviClaValue_1", dpClass : ".do1value" },
	{ dpName: "DO-2", dpReadPath: "Net/LON/iLON App/Digital Output 2/nvoClaValueFb_2", dpWritePath: "Net/LON/iLON App/Digital Output 2/nviClaValue_2", dpClass : ".do2value" },
	{ dpName: "DI-1", dpReadPath: "Net/LON/iLON App/Digital Input 1/nvoClsValue_1"   , dpWritePath: ""  											 , dpClass : ".di1value" },
	{ dpName: "DI-1", dpReadPath: "Net/LON/iLON App/Digital Input 2/nvoClsValue_2"   , dpWritePath: ""  											 , dpClass : ".di2value" }
];

	
// MVC model
var model = null;
var view = null;
var controller = null;


/*		
var do1 = "Binder5/LON/ILON151/Digital Output 1/nviClaValue_1",
do2 = "Binder5/LON/ILON151/Digital Output 2/nviClaValue_2",
do1fb = "Binder5/LON/ILON151/Digital Output 1/nvoClaValueFb_1",
do2fb = "Binder5/LON/ILON151/Digital Output 2/nvoClaValueFb_2";
*/


function RefreshFreqFromSettings() {
	// update ref freq
	return $("#refreshFreq").val();
}

function StopAutoRefresh() {
	$(document).stopTime("RefreshVisiblePoints");
}

function StartAutoRefresh() {
	// set new timer
	if(controller) {
		$(document).everyTime(refreshFreq + "ms", "RefreshVisiblePoints", controller.RefreshVisiblePoints, 0); // 0 means repeat indefinitely
	}
}

function SetRefreshFreq(freq) {
	StopAutoRefresh();
	// update ref freq
	refreshFreq = freq;  // in ms
	StartAutoRefresh();
}

var Controller = function() {
	
	// ask the view what data points are in need of a refresh (e.g. those visible on the current html page) and then
	// tell the model to regularly refesh those points into cache
	this.RefreshVisiblePoints = function() {
		// the array of simple dpPaths
		var list = [];
			
		// for each dp under observation, find those that are actually in the visible page; no point updating them otherwise
		list = view.GetPointsToRefresh();
		
		// if there are indeed visible points to update, update them
		if (list.length !== 0) {
			model.UpdateObservedDataPoints(list);

			// set ref freq to the settings value: assuming the user will actually stay on the current page with some visible points
			if (refreshFreq !== RefreshFreqFromSettings()) {
				SetRefreshFreq(RefreshFreqFromSettings());
			}
			
		} else {
			// if there were no visible points to update, set the ref freq to a faster one, so to be faster to update the UI as soon as
			// the user changes page
		    console.log("No visible points to update, fast refreshing");
			if (refreshFreq !== FAST_REFRESH_FREQ) {
				SetRefreshFreq(FAST_REFRESH_FREQ);
			}
		}
	};
	
	// updates the DOM of the dps sing the original points hash as map dp=>DOM element
	this.DpCacheUpdated = function() {
		
		// for every observed point
		$.each(observedDataPoints_Arr, function(index, value) {
			
			var sel = value.dpClass;
			var newValue = model.DataPoint(value.dpReadPath).CurrentPresetOrValue();
			
			// if they have never appeared on a .current DIV, some points might not have ever been read
			// and therefore might not exist in the local cache. If that's the case just skip to next
			if (!newValue) return;
			
			// tell the view to update the elements
			view.UpdateElementsbySelectorWithValue(sel, newValue);
		});
	};
};


// jQuery documentReady execution
$(function() {

	// set up the MVC objects 
	controller = new Controller();
	model = new LCMVC_model.oDpCache(controller.DpCacheUpdated);
	view = new LCMVC_view.oView();
	
	// set up list of DPs to monitor
	$.each(observedDataPoints_Arr, function(index, value) {
		model.ObserveDataPointPath(this.dpReadPath);
	});
		
	// start monitoring with fast freq, assuming on the first page there are no visible points
	SetRefreshFreq(FAST_REFRESH_FREQ);


	/////// UI events listeners //////////////

	// handle change() in refresh freq
	$("#refreshFreq").change(function() {
		SetRefreshFreq(RefreshFreqFromSettings());
	}).change();

	// set up click() listeners for each point class
	$.each(observedDataPoints_Arr, function(index, value) {
		
		// this refers to the current element of the array, in this case our dp object
		var dpClass = this.dpClass;
		var dpPath = this.dpWritePath; 
		
		// if read only dp, just set to ignore the clicks
		if (dpPath === "") {
			$(dpClass).click( function() {
				return false; // inhibit the click
			});
			return;
		}
		// if not, set the events to handle the clicks:

		//  mousedown() comes before change()
		$(dpClass).mousedown(function() {
			// suspend the autorefresh timer
			//console.log("this = " + this);
			//console.log("$.(this) = " + $(this))
			console.log("Suspending autorefresh on mousedown()");
			StopAutoRefresh();
		});
		
		// actually change the value and resume the autorefresh timer
		$(dpClass).change(function() {
			
			var newValue;	
		
			// get the new value from the DOM itself
			if (this.nodeName.toLowerCase() === "input") {
				// if it's a checkbox
				newValue = ($(this).attr('checked')) == true? "ON" : "OFF";
			} else 	{
				// if it's something else (select, slider, etc.)
				newValue = $(this).val();
			}
		
			// if the user clicks on the non-preset read-only value, ignore the selection
			if (newValue === "Hidden") {
				return false;
			}
			
			console.log("New value: " + newValue);
			
			// set new state and request controller to update the UI on success via callback
			model.Write(dpPath, newValue, function(data, textStatus, xmlHttpRequest) {
				console.log("Write success status: " + textStatus);
				
				// This is tricky:
				// I can call controller.RefreshVisiblePoints() right here, therefore forcing a Read() of the visible dps
				// and the UI will be refreshed; the problem is that the Read() is done too quickly: before the network can actually
				// propagate the change and have some f/b coming back is there is any. On the ilonss or example, if I bind the output of DO-1 
				// to the input of DO-2 to keep them in sync, the UI refresh will happen before DO-2 is phisically changed on the ilonss
				// so the UI for DO-2 won't change until the next scheduled refresh.
				// Therefore it's better to just set a (temporary) faster refresh freq; it will be reset to the correct value at the next refresh
				// the downside is that the update is less immediate, but at least it is more meaningful
				
				SetRefreshFreq(FAST_REFRESH_FREQ);
			});
		
			console.log("Resuming autorefresh on change()");
			StartAutoRefresh();
		});
	});
});



